#![feature(proc_macro_hygiene, decl_macro)]

use rocket::config::{Config, Environment};
use rocket::http::{ContentType, Status};
use rocket::{get, post, routes};
use rocket::{Data, Response, State};

use std::fs::File;
use std::io::Cursor;
use std::io::prelude::Read;
use std::thread;
use std::sync::mpsc;
use std::sync::mpsc::Sender;
use std::sync::Mutex;

struct SSS {
    out: ws::Sender,
}

// 可变静态变量解决多线程访问的问题：rx 是 !Sync 的
static mut CONFIG: Option<SSS> = None;

fn main() {
    // 创建一个新的通道，tx发送者,rx接收者
    let (tx, rx) = mpsc::channel::<String>();

    thread::spawn(move || {
        // 接收 rx
        thread::spawn(move || {
            for received in rx {
                unsafe {
                    if let Some(sss) = &CONFIG {
                        sss.out.broadcast(received);
                    }
                }
            }
        });

        // 监听 WebSocket
        ws::listen("0.0.0.0:3012", |out| {
            // 初始化 CONFIG
            unsafe {
                if let None = CONFIG {
                    CONFIG = Some(SSS { out: out });
                }
            }

            // return Handler
            |_msg| {
                Ok(())
            }
        }).unwrap();
    });

    let mutex_tx = Mutex::new(tx);
    let index_html = read_file("index.html");

    let config = Config::build(Environment::Development)
        .address("0.0.0.0")
        .port(8000)
        .finalize()
        .unwrap();

    rocket::custom(config)
        .manage(mutex_tx)
        .manage(index_html)
        .mount("/", routes![index, paste])
        .launch();
}

// 获取主页
#[get("/")]
fn index(content_state: State<String>) -> Result<Response<'static>, Status> {
    Response::build()
        .header(ContentType::HTML)
        .sized_body(Cursor::new(content_state.clone()))
        .ok()
}

// 写入剪贴板
#[post("/paste", data = "<content>")]
fn paste(content: Data, tx_state: State<Mutex<Sender<String>>>) -> &'static str {
    let mut paste_string = String::new();
    content.open().read_to_string(&mut paste_string).unwrap();

    // 发送 tx，使其发送 websocket 广播
    if let Ok(tx) = tx_state.lock() {
        tx.send(paste_string);
    }

    "ok"
}

// 读取文件
fn read_file(filename: &str) -> String {
    let mut file = File::open(filename).unwrap();
    let mut contents = String::new();

    file.read_to_string(&mut contents).unwrap();

    contents
}
